package vip.liux.backend.application.service.pay;


import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import vip.liux.application.dots.ListResultDto;
import vip.liux.application.dots.PagedResultDto;
import vip.liux.backend.application.service.pay.dto.order.*;
import vip.liux.contracts.infrastructure.pay.dto.order.ClientPayOrderDto;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;

/**
 * 支付订单 Service 接口
 *
 * @author aquan
 */
public interface PayOrderService {

    /**
     * 获得支付订单
     *
     * @param id 编号
     * @return 支付订单
     */
    PayOrderDto getOrder(Long id);

    /**
     * 获得支付订单
     *
     * @param appId           应用编号
     * @param merchantOrderId 商户订单编号
     * @return 支付订单
     */
    PayOrderDto getOrder(Long appId, String merchantOrderId);

    /**
     * 根据订单号获取支付订单
     *
     * @param orderNo 订单号
     * @return 支付订单
     */
    PayOrderDto getByOrderNo(String orderNo);

    /**
     * 获得支付订单详情
     *
     * @param id 编号
     * @return 支付订单详情
     */
    PayOrderDetailsDto getOrderDetail(Long id);

    /**
     * 获得支付订单列表
     *
     * @param ids 编号数组
     * @return 支付订单列表
     */
    ListResultDto<PayOrderDto> getOrderList(Collection<Long> ids);

    /**
     * 获得指定应用的订单数量
     *
     * @param appId 应用编号
     * @return 订单数量
     */
    Long getOrderCountByAppId(Long appId);

    /**
     * 获得支付订单分页
     *
     * @param pageDto 分页查询
     * @return 支付订单分页
     */
    PagedResultDto<PayOrderDto> getOrderPage(PayOrderQueryDto pageDto);

    /**
     * 获得支付订单列表, 用于 Excel 导出
     *
     * @param exportDto 查询条件
     * @return 支付订单列表
     */
    ListResultDto<PayOrderDto> getOrderList(PayOrderExportDto exportDto);

    /**
     * 创建支付单
     *
     * @param input 创建请求
     * @return 支付单编号
     */
    String createOrder(@Valid PayOrderCreateDto input);

    /**
     * 提交支付
     * 此时，会发起支付渠道的调用
     *
     * @param input  提交请求
     * @param userIp 提交 IP
     * @return 提交结果
     */
    PayOrderSubmitDto submitOrder(@Valid PayOrderSubmitInputDto input,
                                  @NotEmpty(message = "提交 IP 不能为空") String userIp);

    /**
     * 通知支付单成功
     *
     * @param channelId 渠道编号
     * @param notify    通知
     */
    void notifyOrder(Long channelId, ClientPayOrderDto notify);

    /**
     * 更新支付订单的退款金额
     *
     * @param orderNo              编号
     * @param incrRefundPrice 增加的退款金额
     */
    void updateOrderRefundPrice(String orderNo, BigDecimal incrRefundPrice);

    /**
     * 更新支付订单价格
     *
     * @param orderNo       支付单编号
     * @param payPrice 支付单价格
     */
    void updatePayOrderPrice(String orderNo, BigDecimal payPrice);

    /**
     * 同步订单的支付状态
     *
     * @param minCreationTime 最小创建时间
     * @return 同步到已支付的订单数量
     */
    int syncOrder(LocalDateTime minCreationTime);

    /**
     * 同步订单的支付状态
     * <p>
     * 1. Quietly 表示，即使同步失败，也不会抛出异常
     * 2. 什么时候回出现异常？因为是主动同步，可能和支付渠道的异步回调存在并发冲突，导致抛出异常
     *
     * @param id 订单编号
     */
    void syncOrderQuietly(Long id);

    /**
     * 将已过期的订单，状态修改为已关闭
     *
     * @return 过期的订单数量
     */
    int expireOrder();
}
